#ifndef FILE_HPP
#define FILE_HPP
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "flash.hpp"
#include "sdk_config.h"

#define FILE_FLAG_NORMALFILE	0x20211101
#define FILE_FLAG_RECORDFILE	0x20220401
#define FILE_NAME_LEN					16
#define FILE_RW_BUFF_LEN			16

using namespace device;
///> 文件保存系统底层
namespace storage
{
	class file
	{	
		public:
			typedef enum
			{
				DISK_NONE = -1,
#ifdef MANUAL_FLASH_ADDR_S1
				DISK_1,
#endif
#ifdef MANUAL_FLASH_ADDR_S2
				DISK_2,
#endif
#ifdef MANUAL_FLASH_ADDR_S3
				DISK_3,
#endif
#ifdef MANUAL_FLASH_ADDR_S4
				DISK_4,
#endif
			}DiskTPDF;
			
			typedef struct
			{
				uint16_t usRecordID;		///<事件记录ID
				uint16_t usItemSize;		///<单条记录数据大小
				uint16_t usItemLength;	///<记录数量
				uint16_t Reserver;			///<保留
			}RecordInitTPDF;					///<记录初始化定义故障记录
			
		private:
			typedef enum
			{
				DISK_TYPE_FILE = FILE_FLAG_NORMALFILE,	///<普通文件
				DISK_TYPE_RECORD = FILE_FLAG_RECORDFILE,///<记录
				DISK_TYPE_ALL = 1,											///<所有
			}DiskTypeTPDF;														///<盘类型
		
			typedef struct
			{
				char Name[FILE_NAME_LEN];								///<文件名
				uint32_t Handle;												///<文件句柄(文件数据地址)
				uint32_t FileLen;												///<文件长度
				uint32_t CheckSum;											///<文件校验和
				uint32_t Flag;													///<标记位
			}FileInforTPDF;														///<文件信息头定义

			typedef struct
			{
				uint32_t Reserver[2];										///<保留
				uint32_t Counter;												///<版本计数值
				uint32_t Flag;													///<标记
			}SectorInforTPDF;													///<扇区信息
			
			typedef struct
			{
				RecordInitTPDF tRecordInit;							///<记录初始化
				uint32_t uiReserver;										///<保留
				uint32_t uiFlag;												///<标记位
			}RecordInitPackTPDF;											///<记录信息包

			typedef struct
			{
				uint32_t uiOffset;											///<后续偏移量
				uint32_t uiCheckSum;										///<校验和
				uint32_t uiFlag;												///<标记位
			}RecordHeadTPDF;													///<记录头定义
			
			static flash* mFlash;											///<flash接口
			
			/** 
			* @brief      	获取盘可用的扇区
			* @param[in]  	tDisk   		盘
			* @param[in]  	tType   		盘类型
			* @retval     	扇区地址
			*/
			static int32_t GetUseableAddr(file::DiskTPDF tDisk,DiskTypeTPDF tType);
			
			/** 
			* @brief      	获取扇区计数值
			* @param[in]  	uiAddr   		扇区地址
			* @retval     	计数值
			*/
			static uint32_t GetCounter(uint32_t uiAddr);
			/** 
			* @brief      	获取扇区对应的无用扇区(对立的扇区)
			* @param[in]  	tDisk   		盘
			* @param[in]  	uiAddr   		扇区地址
			* @retval     	扇区地址
			*/
			static uint32_t GetUseLessAddr(file::DiskTPDF tDisk, uint32_t uiAddr);
			
			/** 
			* @brief      	擦除扇区
			* @param[in]  	tDisk   		盘
			* @param[in]  	uiAddr   		扇区地址
			* @retval     	None
			*/
			static void EraseBank(file::DiskTPDF tDisk, uint32_t uiAddr);
			
			/** 
			* @brief      	查找文件
			* @param[in]  	uiAddr   		扇区地址
			* @param[in]  	cName   		文件名
			* @param[in]  	tFileInfor 	文件信息
			* @param[in]  	bLast   		是否查找最后一份文件
			* @retval     	文件句柄
			*/
			static int32_t FileFind(uint32_t uiAddr, const char* cName, FileInforTPDF *tFileInfor, bool bLast);
			
			/** 
			* @brief      	查找最后一次记录
			* @param[in]  	tDisk   					盘
			* @param[in]  	uiAddr   					扇区地址
			* @param[in]  	tRecordInitPack   记录初始化信息
			* @param[in]  	uiMaxRecord   		最大记录数量
			* @retval     	记录索引号
			*/
			static int32_t RecordFindLast(DiskTPDF tDisk, uint32_t uiAddr, RecordInitPackTPDF *tRecordInitPack, uint32_t uiMaxRecord);
			
			/** 
			* @brief      	将记录拷贝至对立扇区
			* @param[in]  	tDisk   						盘
			* @param[in]  	uiOldAddr   				旧扇区地址
			* @param[in]  	uiNewAddr   				新扇区地址
			* @param[in]  	tRecordInitPack   	记录初始化信息
			* @param[in]  	ucExceptRecordData  新记录
			* @param[in]  	uiLasetRecordIndex	最后一次记录
			* @retval     	操作结果
			*/
			static bool RecordMoveSector(DiskTPDF tDisk, uint32_t uiOldAddr, uint32_t uiNewAddr, RecordInitPackTPDF *tRecordInitPack, uint8_t *ucExceptRecordData, uint32_t uiLasetRecordIndex);
			
			/** 
			* @brief      	将文件拷贝至对立扇区
			* @param[in]  	tDisk   					盘
			* @param[in]  	uiOldAddr   			旧扇区地址
			* @param[in]  	uiNewAddr   			新扇区地址
			* @param[in]  	cExceptFileName   迁移过程中需要更新的文件名
			* @param[in]  	ucExceptFileData  更新的文件数据
			* @param[in]  	usExceptFileLen		更新的文件长度
			* @retval     	操作结果(文件写满会返回false)
			*/
			static bool FileMoveSector(DiskTPDF tDisk, uint32_t uiOldAddr, uint32_t uiNewAddr, const char* cExceptFileName, uint8_t *ucExceptFileData, uint16_t usExceptFileLen);
		public:
			
			/** 
			* @brief      	文件读取
			* @param[in]   	tDisk	文件盘
			* @param[in]   	cName	文件名
			* @param[in]   	ucData	数据
			* @param[in]   	usLen	数据长度
			* @retval    	 	操作结果
			*/
			static bool Read(DiskTPDF tDisk, const char* cName, uint8_t *ucData, uint16_t usLen);
			
			/** 
			* @brief      	记录读取
			* @param[in]   	tDisk				文件盘
			* @param[in]   	usRecordID	记录ID
			* @param[in]   	usIndex			索引号(0表示最近一条)
			* @param[in]   	ucData			数据
			* @param[in]   	usLen				数据长度
			* @retval    	 	操作结果
			*/
			static bool Read(DiskTPDF tDisk, uint16_t usRecordID, uint16_t usIndex, uint8_t *ucData, uint16_t usLen);
			
			/** 
			* @brief      	写文件
			* @param[in]   	tDisk	文件盘
			* @param[in]   	cName	文件名
			* @param[in]   	ucData	数据
			* @param[in]   	usLen	数据长度
			* @retval    	 	操作结果
			*/
			static bool Write(DiskTPDF tDisk, const char* cName, uint8_t *ucData, uint16_t usLen);
			
			/** 
			* @brief      	写记录
			* @param[in]   	tDisk				文件盘
			* @param[in]   	usRecordID	记录ID
			* @param[in]   	ucData			数据
			* @param[in]   	usLen				数据长度
			* @retval    	 	操作结果
			*/
			static bool Write(DiskTPDF tDisk, uint16_t usRecordID, uint8_t *ucData, uint16_t usLen);
			
			/** 
			* @brief      	删除文件
			* @param[in]   	tDisk	文件盘
			* @param[in]   	cName	文件名
			* @retval    	 	操作结果
			*/
			static bool Delete(DiskTPDF tDisk, const char* cName);
			
			/** 
			* @brief      	格式化盘
			* @param[in]   	tDisk	文件盘
			* @retval    	 	操作结果
			*/
			static bool Format(DiskTPDF tDisk);
			
			/** 
			* @brief      	文件初始化
			* @param[in]   	tFls	存储器
			* @retval    	 	None
			*/
			static void Init(flash *tFls);
			
			/** 
			* @brief      	记录初始化
			* @param[in]   	tDisk	文件盘
			* @param[in]   	tRecordInit	记录初始化
			* @retval    	 	None
			*/
			static bool RecordInit(DiskTPDF tDisk, RecordInitTPDF *tRecordInit);
	};
}

#endif
